/*
 * Copyright 2017 - 2025 the original author or authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see [https://www.gnu.org/licenses/]
 */

package infra.bytecode.core;

import org.jspecify.annotations.Nullable;

import java.util.function.Predicate;

/**
 * Customize the generated class name for {@link AbstractClassGenerator}-based
 * utilities.
 *
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
 */
@FunctionalInterface
public interface NamingPolicy {

  /**
   * Choose a name for a generated class.
   *
   * @param prefix a dotted-name chosen by the generating class (possibly to put the
   * generated class in a particular package)
   * @param source the class simple name of the generating class
   * @param key A key object representing the state of the parameters; for caching
   * to work properly, equal keys should result in the same generated
   * class name. The default policy incorporates
   * <code>key.hashCode()</code> into the class name.
   * @param names a predicate that returns true if the given classname has already
   * been used in the same ClassLoader.
   * @return the fully-qualified class name
   */
  String getClassName(@Nullable String prefix, String source, Object key, Predicate<String> names);

  /**
   * The <code>NamingPolicy</code> in use does not currently, but may in the
   * future, affect the caching of classes generated by
   * {@link AbstractClassGenerator}, so this is a reminder that you should
   * correctly implement <code>equals</code> and <code>hashCode</code> to avoid
   * generating too many classes.
   */
  boolean equals(Object o);

  static InfraNamingPolicy forInfrastructure() {
    return InfraNamingPolicy.INSTANCE;
  }

}
